/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package egovxf.web;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.WebRequestDataBinder;

import org.springframework.web.context.request.WebRequest;

import egovxf.service.PatternService;

/**
 * Service Broker Controller.
 * <p/>
 * <b>NOTE</b>: 
 * @author 딸기아빠 (committer)
 * @since 2011.04.06
 * @version 1.0
 * @see <pre>
 *  == 개정이력(Modification Information) ==
 *   
 *   수정일      수정자           수정내용
 *  -------    --------    ---------------------------
 *   2011.04.06  딸기아빠          최초 생성
 * 
 * </pre>
 */
@Controller
public class ServiceBrokerController implements ApplicationContextAware {
    @Resource(name="patternService")
    private PatternService patternService;
    
    private ApplicationContext applicationContext;
    
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
	this.applicationContext = applicationContext;
    }
 
	protected Object resolveServiceBean(String domain, String methodName) {
		Object serviceBean = applicationContext.getBean(domain+"Service");
		return serviceBean;
	}
    @RequestMapping("/service/broker/list.do")
    public String selectList(
	    @RequestParam("queryId") String brokerQueryId,
	    @RequestParam("viewName") String brokerViewName,
	    @ModelAttribute("model") Map<String, Object> commandMap,
	    WebRequest request,
	    ModelMap model) throws Exception {

		Object serviceBean = applicationContext.getBean("patternService");
		Method method = resolveMethod("list", serviceBean);

    	Object[] args = bindArguments(method, request);
    	
	List<Map<String, Object>> result = patternService.mlist(brokerQueryId, commandMap);
	    
	model.addAttribute("brokerResult", result);
	
	return brokerViewName;
    }
    
    @RequestMapping("/service/broker/select.do")
    public String selectDetail(
	    @RequestParam("queryId") String brokerQueryId,
	    @RequestParam("viewName") String brokerViewName,
	    @ModelAttribute("model") Map<String, Object> commandMap,
	    WebRequest request,
	    ModelMap model) throws Exception {
	
	Map<String, Object> result = patternService.select(brokerQueryId, commandMap );
	    
	model.addAttribute("brokerResult", result);
	
	return brokerViewName;
    }
    
    @RequestMapping("/service/broker/insert.do")
    public String insert(
	    @RequestParam("queryId") String brokerQueryId,
	    @RequestParam("viewName") String brokerViewName,
	    @ModelAttribute("model") Map<String, Object> commandMap,
	    ModelMap model) throws Exception {
	
    	patternService.insert(brokerQueryId, commandMap);
	
	return brokerViewName;
    }
    
    @RequestMapping("/service/broker/update.do")
    public String update(
	    @RequestParam("queryId") String brokerQueryId,
	    @RequestParam("viewName") String brokerViewName,
	    @ModelAttribute("model") Map<String, Object> commandMap,
	    ModelMap model) throws Exception {
	
    	patternService.update(brokerQueryId, commandMap);
	
	return brokerViewName;
    }
    
    @RequestMapping("/service/broker/delete.do")
    public String delete(
	    @RequestParam("queryId") String brokerQueryId,
	    @RequestParam("viewName") String brokerViewName,
	    @ModelAttribute("model") Map<String, Object> commandMap,
	    ModelMap model) throws Exception {
	
    	patternService.delete(brokerQueryId, commandMap);
	
	return brokerViewName;
    }
    
    @RequestMapping("/service/broker/service.do")
    public String service(
	    @RequestParam("serviceId") String brokerServiceId,
	    @RequestParam("serviceMethod") String brokerServiceMethod,
	    @RequestParam("viewName") String brokerViewName,
	    @ModelAttribute("model") Map<String, Object> commandMap,
	    ModelMap model) throws Exception {
	
	Object target = applicationContext.getBean("brokerServiceId");
	
	Method candidates[] = ReflectionUtils.getAllDeclaredMethods(target.getClass());
	Method candidate = null;
	
        for (int i = 0; i < candidates.length; i++) {
            candidate = candidates[i];
            if (candidate.getName().equals(brokerServiceMethod)) {
                break;
            }
        }
        
        if (candidate == null) {
            throw new IllegalArgumentException("Service method not found : " + brokerServiceMethod);
        }
            
        Class<?> paramTypes[] = candidate.getParameterTypes();
        System.out.println(candidate.getReturnType().getName());
        for (int i = 0; i < paramTypes.length; i++) {
            System.out.println(paramTypes[i].getCanonicalName());
            if (paramTypes[i].getCanonicalName().equals("")) {
        	
            } else {
        	// TODO
            }
        }
        
	return brokerViewName;
    }
    
	protected Object[] bindArguments(Method method, WebRequest request) {
		return resolveArguments(method.getParameterTypes(), request);
	}
	
	public static Object[] resolveArguments(Class<?>[] types, WebRequest request) {
		Object[] target = new Object[types.length];
		for (int i = 0; i < types.length; i++) {
			if(BeanUtils.isSimpleProperty(types[i])) {
				throw new RuntimeException("LControllerGate doesn't support service method with parameter type of [primitive, String, Number, Date, URI, URL, Locale, Class].");

			}else if(HashMap.class.equals(types[i])){
				target[i] = resolveHashMap(request);

			}else{
				target[i] = BeanUtils.instantiateClass(types[i]);
				new WebRequestDataBinder(target[i], "").bind(request);
			}
		}

//		processCGateSessionField(request, target);

		return target;
	}
	
	public static Method resolveMethod(String methodName, Object service) {
		Method[] methods = service.getClass().getMethods();

		Method result = null;
		for (int i = 0; i < methods.length; i++) {
			if(methods[i].getName().equals(methodName)) {
				if(result == null) {
					result = methods[i];
				}else{
					throw new RuntimeException("@Service methodName must be unique. Duplicated method name is ["+methodName+"()].");
				}
			}
		}

		return result;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static HashMap resolveHashMap(WebRequest webRequest) {

		Map<String, String[]> parameterMap = webRequest.getParameterMap();
		HashMap hm = new LinkedHashMap();

		Iterator iter = parameterMap.keySet().iterator();
		while (iter.hasNext()) {
			String key = (String) iter.next();
			if(parameterMap.get(key).length == 1) {
				hm.put(key, parameterMap.get(key)[0]);

			}else if(parameterMap.get(key).length > 1){
				hm.put(key, parameterMap.get(key));
			}
		}

		return hm;
	}
}
